package com.itbaizhan.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.itbaizhan.api.UserAccountBank02Service;
import com.itbaizhan.dto.UserAccountDTO;

import com.itbaizhan.entity.CancelLog;
import com.itbaizhan.entity.ConfirmLog;
import com.itbaizhan.entity.TryLog;
import com.itbaizhan.entity.UserAccount;
import com.itbaizhan.mapper.CancelLogMapper;
import com.itbaizhan.mapper.ConfirmLogMapper;
import com.itbaizhan.mapper.TryLogMapper;
import com.itbaizhan.mapper.UserAccountMapper;


import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 * 账户信息 服务实现类
 * </p>
 *
 * @author itbaizhan
 * @since 07-08
 */
@Slf4j
@DubboService(version = "1.0.0")
public class UserAccountServiceImpl  implements UserAccountBank02Service {

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Resource
    private TryLogMapper tryLogMapper;
    @Resource
    private ConfirmLogMapper confirmLogMapper;
    @Resource
    private CancelLogMapper cancelLogMapper;
    /**
     * 跨库转账，这里是转入
     * @param userAccountDTO
     */
  //  @Transactional(rollbackFor = Exception.class)   注意使用HmilyTCC 不可以用@Transactional，否则会出现数据库存的数据错误
    @HmilyTCC(confirmMethod = "sayConfrim", cancelMethod = "sayCancel")
    @Override
    public void transferAmountToBank02(UserAccountDTO userAccountDTO) {

        String txNo = userAccountDTO.getTxNo(); //在controllerUUID生成
        log.info("****** 执行bank02 的 Try方法，事务id={}",txNo);

        //1，幂等处理
        TryLog tryLog = tryLogMapper.selectById(txNo);
        if(tryLog != null){  //如果处理过直接返回
            return;
        }
        //2, 悬挂处理
        if(confirmLogMapper.selectById(txNo) != null || cancelLogMapper.selectById(txNo) != null){
            return;
        }

        //1.根据账户编号查询账户信息,这里可以用baseMapper,
        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getTargetAccountNo());

        //2判断账户是否存在
        if(userAccount != null){
            //更新账户
            LambdaUpdateWrapper<UserAccount> ulw = new LambdaUpdateWrapper<>();
            //更新转账金额
            ulw.set(UserAccount::getTransferAmount,userAccount.getTransferAmount().add(userAccountDTO.getBigDecimal()));

            ulw.eq(UserAccount::getAccountNo,userAccountDTO.getTargetAccountNo());
            //ulw是查询条件
            userAccountMapper.update(null,ulw);


        }

        //3. 准备阶段记录
        TryLog tryLog1 = new TryLog();
        tryLog1.setTxNo(txNo);
        tryLog1.setCreateTime(LocalDateTime.now());
        tryLogMapper.insert(tryLog1);


    }

    /**
     * 确认阶段
     * @param userAccountDTO
     * @HmilyTCC(confirmMethod = "sayConfrim", cancelMethod = "sayCancel")    方法名必须与里面的参数一样
     */
    public void sayConfrim(UserAccountDTO userAccountDTO){
        String txNo = userAccountDTO.getTxNo(); //在controllerUUID生成
        log.info("****** 执行bank02 的 confrim方法，事务id={}",txNo);

        /*这里是转入账户
         * 确认阶段就是把表里的要转账金额的字段，修改为原来的多小,账户的余额 + 转入的金额*/
        //1，幂等处理
        ConfirmLog confirmLog = confirmLogMapper.selectById(txNo);
        //如果查询到，说明已运行了一次不用再重复运行
        if(confirmLog != null){
            return;
        }
        //2更新操作
        //2.1 根据id查询账户
        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getTargetAccountNo());
        //修改余额
        userAccount.setAccountBalance(userAccount.getAccountBalance().add(userAccountDTO.getBigDecimal()));
        //修改要转账金额的字段
        userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getBigDecimal()));
        userAccountMapper.updateById(userAccount);

        //3,确认日志记录
        ConfirmLog confirmLog1 = new ConfirmLog();
        confirmLog1.setTxNo(txNo);
        confirmLog1.setCreateTime(LocalDateTime.now());
        confirmLogMapper.insert(confirmLog1);
    }

    /**
     * 取消阶段
     * @param userAccountDTO
     * @HmilyTCC(confirmMethod = "sayConfrim", cancelMethod = "sayCancel")    方法名必须与里面的参数一样
     */
    public void sayCancel(UserAccountDTO userAccountDTO){
        String txNo = userAccountDTO.getTxNo(); //在controllerUUID生成
        log.info("****** 执行bank02 的 cancel方法，事务id={}",txNo);


        //2更新操作
        //2.1 根据id查询账户
        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getTargetAccountNo());
        //修改转账金额，
        userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getBigDecimal()));
         userAccountMapper.updateById(userAccount);

        //3,记录日志
        CancelLog cancelLog1 = new CancelLog();
        cancelLog1.setTxNo(txNo);
        cancelLog1.setCreateTime(LocalDateTime.now());
        cancelLogMapper.insert(cancelLog1);
    }
}
